﻿//
// © Algobox Ltd - Benn Eichhorn
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Algobox.Objects.Finance.Assets.Stock;
using Algobox.Objects.Finance;
using Algobox.Objects.Finance.Assets;
using System.Collections.Concurrent;
using Algobox.Structure.Finance.Strategies.SpikeArb;

namespace Algobox.Data.Finance.LiquidView
{
    public class LiquidViewDataInterface : ISpikeArbData
    {
        public LiquidViewDataInterface(ConcurrentDictionary<string, StockSecurity> securities)
        {
            _stocks = securities;
            _linq = new LiquidViewLinqDataContext();
            TryLoadStocks();
        }

        public LiquidViewDataInterface(ConcurrentDictionary<string, StockSecurity> securities, string connection)
        {
            _stocks = securities;
            _linq = new LiquidViewLinqDataContext(connection);
            TryLoadStocks();
        }

        public LiquidViewDataInterface(ConcurrentDictionary<string, StockSecurity> securities, System.Data.IDbConnection connection)
        {
            _stocks = securities;
            _linq = new LiquidViewLinqDataContext(connection);
            TryLoadStocks();
        }

        ConcurrentDictionary<string, StockSecurity> _stocks;
        public IDictionary<string, StockSecurity> Stocks { get { return _stocks; } }
        
        private LiquidViewLinqDataContext _linq;
        
        public string FeedName
        {
            get { return "LiquidViewDataInterface"; }
        }
        
        public bool TryLoadStrategySpikeArb(SpikeArbManagement spikeArb)
        {
            Markets.MarketMIC market;
            Currencies.Currency currency;
            try
            {
                //foreach (ViewStrategySpikeArbSetting arb in _linq.ViewStrategySpikeArbSettings.Where(a => a.SterlingTrader == "VOD.LN" || a.SterlingTrader == "LLOY.LN" || a.SterlingTrader == "BARC.LN" || a.SterlingTrader == "RIO.LN"))
                foreach (ViewStrategySpikeArbSetting arb in _linq.ViewStrategySpikeArbSettings.Where(a => a.IndexId == "FTSE100"))
                {
                    if (Enum.TryParse<Markets.MarketMIC>(arb.MarketMIC, out market)
                            && Enum.TryParse<Currencies.Currency>(arb.Currency, out currency))
                    {
                        if (currency == Currencies.Currency.GBP)
                            currency = Currencies.Currency.GBX;

                        // try and load existing stock or create it if not found
                        StockSecurity stock = _stocks.AddOrUpdate(arb.SterlingTrader,
                            (inSymbol) =>
                            {
                                return new StockSecurity(arb.SterlingTrader, market)
                                {
                                    Currency = currency,
                                    Index = arb.IndexId,
                                    Sector = arb.Sector,
                                    IndustryGroup = arb.IndustryGroup,
                                    Industry = arb.Industry,
                                    ISIN = arb.ISIN
                                };
                            },
                            (inSymbol, inStock) =>
                            {
                                return inStock;
                            });

                        spikeArb.AddOrUpdate(
                            arb.StockId,
                            stock,
                            arb.IsEnabledPrimary, arb.IsEnabledChix, arb.IsEnabledBATE,
                            arb.Band1Enabled, arb.Band1Value, arb.Band1Percent, arb.Band1Window,
                            arb.Band2Enabled, arb.Band2Value, arb.Band2Percent, arb.Band2Window,
                            arb.Band3Enabled, arb.Band3Value, arb.Band3Percent, arb.Band3Window,
                            arb.Band4Enabled, arb.Band4Value, arb.Band4Percent, arb.Band4Window
                        );
                    }
                }
                return true;
            }
            catch
            {

            }
            return false;
        }

        public bool TrySaveStrategySpikeArb(SpikeArbManagement spikeArb)
        {
            try
            {
                // save manager settings here
                // TODO: Load manager settings

                // save stock and leg settings here
                foreach (Algobox.Structure.Finance.Strategies.SpikeArb.SpikeArbStock arb in spikeArb.Strategies.Values)
                {
                    StrategySettingsSpikeArb row = _linq.StrategySettingsSpikeArbs.SingleOrDefault(
                        s => s.StockId == arb.Id);

                    if (row != default(StrategySettingsSpikeArb))
                    {
                        row.IsEnabledPrimary = arb.ListingPrimary.IsEnabled;
                        row.IsEnabledChix = arb.ListingChix.IsEnabled;
                        row.IsEnabledBATE = arb.ListingBats.IsEnabled;
                        row.Band1Enabled = arb.Collar1.IsEnabled;
                        row.Band1Value = (decimal)arb.Collar1.Value;
                        row.Band1Percent = (decimal)arb.Collar1.Percentage;
                        row.Band1Window = (decimal)arb.Collar1.Window;
                        row.Band2Enabled = arb.Collar2.IsEnabled;
                        row.Band2Value = (decimal)arb.Collar2.Value;
                        row.Band2Percent = (decimal)arb.Collar2.Percentage;
                        row.Band2Window = (decimal)arb.Collar2.Window;
                        row.Band3Enabled = arb.Collar3.IsEnabled;
                        row.Band3Value = (decimal)arb.Collar3.Value;
                        row.Band3Percent = (decimal)arb.Collar3.Percentage;
                        row.Band3Window = (decimal)arb.Collar3.Window;
                        row.Band4Enabled = arb.Collar4.IsEnabled;
                        row.Band4Value = (decimal)arb.Collar4.Value;
                        row.Band4Percent = (decimal)arb.Collar4.Percentage;
                        row.Band4Window = (decimal)arb.Collar4.Window;
                    }
                }
                _linq.SubmitChanges();

                return true;
            }
            catch
            { 
            }
            return false;
        }

        private bool TryLoadStocks()
        {
            try
            {
                // load all FTSE symbols with sterling codes
                Markets.MarketMIC market;
                Currencies.Currency currency;
                foreach (var security in _linq.ViewInstrumentsStocks.Where(a => (a.IndexId == "FTSE100" || a.IndexId == "FTSE250") && a.SterlingTrader != null))
                {
                    if (Enum.TryParse<Markets.MarketMIC>(security.MarketMIC, out market)
                            && Enum.TryParse<Currencies.Currency>(security.Currency, out currency))
                    {
                        if (currency == Currencies.Currency.GBP)
                            currency = Currencies.Currency.GBX;

                        // try and load existing stock or create it if not found
                        if (!_stocks.ContainsKey(security.SterlingTrader))
                        {
                            _stocks.TryAdd(security.SterlingTrader,
                                new StockSecurity(security.SterlingTrader, market)
                                {
                                    Currency = currency,
                                    Index = security.IndexId,
                                    Sector = security.IndustrySub,
                                    IndustryGroup = security.Industry,
                                    Industry = security.IndustryGroup,
                                    ISIN = security.ISIN
                                });
                        }
                    }
                }

                // load spike stocks
                foreach (ViewStrategySpikeArbSetting arb in _linq.ViewStrategySpikeArbSettings.Where(a => a.SterlingTrader != null))
                {
                    if (Enum.TryParse<Markets.MarketMIC>(arb.MarketMIC, out market)
                            && Enum.TryParse<Currencies.Currency>(arb.Currency, out currency))
                    {
                        if (currency == Currencies.Currency.GBP)
                            currency = Currencies.Currency.GBX;

                        // try and load existing stock or create it if not found
                        if (!_stocks.ContainsKey(arb.SterlingTrader))
                        {
                            _stocks.TryAdd(arb.SterlingTrader,
                                new StockSecurity(arb.SterlingTrader, market)
                                {
                                    Currency = currency,
                                    Index = arb.IndexId,
                                    Sector = arb.Sector,
                                    IndustryGroup = arb.IndustryGroup,
                                    Industry = arb.Industry,
                                    ISIN = arb.ISIN
                                });
                        }                        
                    }
                }


                Exchanges.ExchangeMIC exchange = Exchanges.ExchangeMIC.XXXX;

                ITick tickCacheValue;                                
                Dictionary<string, ITick> tickCache = new Dictionary<string, ITick>();

                var listingData = _linq.ViewInstrumentsStocksListings;

                foreach (StockSecurity security in _stocks.Values)
                {
                    foreach (var query in listingData.Where(a => a.SterlingTrader == security.Symbol))
                    {                            
                        if (query != default(ViewInstrumentsStocksListing)
                            && Enum.TryParse<Exchanges.ExchangeMIC>(query.ExchangeMIC, out exchange)
                            && (exchange == Exchanges.ExchangeMIC.XLON || exchange == Exchanges.ExchangeMIC.CHIX || exchange == Exchanges.ExchangeMIC.BATE))
                        {
                            int priceMultiplier = 1;

                            if (security.Currency == Currencies.Currency.GBX)
                                priceMultiplier = 100;

                            security.Listings.AddOrUpdate(exchange,
                                (key) =>
                                {
                                    StockListing listing;
                                    if (query.TickSize.IsDynamic)
                                    {
                                        if (!tickCache.TryGetValue(query.TickSize.TickSizeName, out tickCacheValue))
                                        {
                                            tickCacheValue = new TickDynamic(query.TickSize.TickSizeName, query.TickSize.TickSizeValues.ToDictionary(a => a.LowerPriceLimit.Value * priceMultiplier, b => b.TickValue * priceMultiplier));
                                            tickCache.Add(query.TickSize.TickSizeName, tickCacheValue);
                                        }
                                        listing = new StockListing(security, exchange, (TickDynamic)tickCacheValue)
                                        {
                                            Bloomberg = query.BloombergListing,
                                            Reuters = query.ReutersListing
                                        };
                                    }
                                    else
                                    {
                                        if (!tickCache.TryGetValue(query.TickSize.TickSizeName, out tickCacheValue))
                                        {
                                            tickCacheValue = new TickStatic(query.TickSize.TickSizeName, query.TickSize.TickSizeValues.First(a => a.TickSizeId == query.TickSizeId).TickValue * priceMultiplier);
                                            tickCache.Add(query.TickSize.TickSizeName, tickCacheValue);
                                        }
                                        listing = new StockListing(security, exchange, (TickStatic)tickCacheValue)
                                        {
                                            Bloomberg = query.BloombergListing,
                                            Reuters = query.ReutersListing
                                        };
                                    }
                                    return listing;
                                },
                                (key, value) =>
                                {
                                    value.Bloomberg = query.BloombergListing;
                                    value.Reuters = query.ReutersListing;
                                    if (value.TickSize == null || value.TickSize.Name != query.TickSize.TickSizeName)
                                    {
                                        if (query.TickSize.IsDynamic)
                                        {
                                            if (!tickCache.TryGetValue(query.TickSize.TickSizeName, out tickCacheValue))
                                            {
                                                tickCacheValue = new TickDynamic(query.TickSize.TickSizeName, query.TickSize.TickSizeValues.ToDictionary(a => a.LowerPriceLimit.Value * priceMultiplier, b => b.TickValue * priceMultiplier));
                                                tickCache.Add(query.TickSize.TickSizeName, tickCacheValue);
                                            }
                                            value.TickSize = (TickDynamic)tickCacheValue;
                                        }
                                        else
                                        {
                                            if (!tickCache.TryGetValue(query.TickSize.TickSizeName, out tickCacheValue))
                                            {
                                                tickCacheValue = new TickStatic(query.TickSize.TickSizeName, query.TickSize.TickSizeValues.First(a => a.TickSizeId == query.TickSizeId).TickValue * priceMultiplier);
                                                tickCache.Add(query.TickSize.TickSizeName, tickCacheValue);
                                            }
                                            value.TickSize = (TickStatic)tickCacheValue;
                                        }
                                    }
                                    return value;
                                });

                        }
                    }
                }                
                return true;
            }
            catch
            {
            }
            return false;
        }


    }
}
